package com.lds.erp.common.util;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ObjectUtils;

import com.dph.common.utils.utils.DESUtils;
import com.dph.common.utils.utils.login.JWTUtils;
import com.lds.erp.mch.mch.ApiCacheConstants;
import com.lds.erp.util.SpringContextUtils;

/**
 * @author hongsir
 * @apiNote 登录账号相关的工具类, 取值, 存值等
 * @date 2018/9/29 上午11:05
 */
public class AccountUtils {
    private static final Logger log = LoggerFactory.getLogger(AccountUtils.class);
    private static final ThreadLocal<AccountCache> LOCAL = new InheritableThreadLocal<>();
    private static RedisTemplate redisTemplate;

    private static RedisTemplate getRedisInstance() {
        if (ObjectUtils.isEmpty(redisTemplate)) {
            redisTemplate = (RedisTemplate) SpringContextUtils.getBean("redisTemplate");
        }
        return redisTemplate;
    }

    /**
     * 删除用户登录信息,根据线程资源移除缓存
     */
    @SuppressWarnings("unchecked")
    public static void remove() {
        if (LOCAL.get() != null) {
            // 清空redis
            String key = ApiCacheConstants.MCH_REDIS_USER_KEY_PREFIX + LOCAL.get().getMchId();
            getRedisInstance().delete(key);
            // 清空线程
            LOCAL.remove();
        }
    }

    /**
     * 根据token移除缓存和线程资源
     *
     * @param token
     */
    @SuppressWarnings("unchecked")
    public static void remove(String token) {
        try {
            String mchId_ = DESUtils.decrypt(token);
            String mchId = mchId_.split("_")[0];
            String key = ApiCacheConstants.MCH_REDIS_USER_KEY_PREFIX + mchId;
            // 清空redis
            getRedisInstance().delete(key);
            // 清空线程
            LOCAL.remove();
        } catch (Exception e) {
            log.error("获取缓存账号信息失败:{}:{}", e.getClass(), e.getMessage());
        }
    }

    /**
     * 缓存账号信息
     * 自动获取token的过期失效同步redis过期时间
     *
     * @param account 账号信息
     */
    @SuppressWarnings("unchecked")
    public static void cacheAccount(AccountCache account) {
        String key = ApiCacheConstants.MCH_REDIS_USER_KEY_PREFIX + account.getMchId();
        getRedisInstance().opsForValue().set(key, account, ApiCacheConstants.MCH_INFO_REDIS_DATE, TimeUnit.SECONDS);
    }

    /**
     * 根据用户ID,强制踢人
     * 用户缓存key规则与cacheAccount()保持一致即可
     * 缓存前缀+用户id+'_'
     * String key = CacheConstants.REDIS_USER_KEY_PREFIX + account.getUserId() + "_" + account.getCacheKey();
     *
     * @param userIdList
     */
    public static void forceRemove(List<String> userIdList) {
        if (!ObjectUtils.isEmpty(userIdList)) {
            Set<String> keys = new HashSet<>();
            for (String userId : userIdList) {
                Set<String> _keys = getRedisInstance().keys(ApiCacheConstants.MCH_REDIS_USER_KEY_PREFIX + userId);
                keys.addAll(_keys);
            }
            getRedisInstance().delete(keys);
        }
    }

    /**
     * 使用token从缓存中获取
     *
     * @param token
     * @return
     */
    public static AccountCache getAccount(String token) {
        try {
            // 根据User服务加密规则解析userId,当前是userId_盐值进行加密的
            String mchId_ = DESUtils.decrypt(token);
            String mchId = mchId_.split("_")[0];
            String key = ApiCacheConstants.MCH_REDIS_USER_KEY_PREFIX + mchId;
            AccountCache cache = (AccountCache) getRedisInstance().opsForValue().get(key);
            if (null != cache && !token.equals(cache.getMchToken())) {
                return null;
            }
            return cache;
        } catch (Exception e) {
            log.error("获取缓存账号信息失败:{}:{}", e.getClass(), e.getMessage());
            return null;
        }
    }

    /**
     * 从线程资源中获取当前账号信息
     */
    public static AccountCache getAccount() {
        return LOCAL.get();
    }


    /**
     * 获取token得过期失效,单位:秒
     *
     * @param token jwt加密的token
     * @return 过期|解析失败时返回-1
     */
    public static long getExpire(String token) {
        long expire;
        try {
            long tokenT = JWTUtils.parseJWT(token).getExpiration().getTime();
            expire = (tokenT - System.currentTimeMillis()) / 1000 + 1;
        } catch (Exception e) {
            expire = -1;
            log.error("token已经失效");
        }
        return expire;
    }


    /**
     * 将用户信息保存到线程资源中
     *
     * @param account
     */
    public static void setAccount(AccountCache account) {
        LOCAL.set(account);
    }
}
